package com.zf.nio.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author Zhou Feng
 */
public class SelectorDemo01 {
    public static void main(String[] args) throws IOException {
        // 1、获取 Selector 选择器
        Selector selector = Selector.open();
        // 2、获取通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 3.设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        // 4、绑定连接
        serverSocketChannel.bind(new InetSocketAddress(9999));
        // 5、将通道注册到选择器上,并制定监听事件为：“接收”事件
        // ServerSocketChannel的有效事件为 OP_ACCEPT。
        // SocketChannel的有效事件为 OP_CONNECT、OP_READ、OP_WRITE
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                if (key.isAcceptable()) {
                    // a connection was accepted by a ServerSocketChannel.
                    // ServerSocketChannel监听到新连接的到来，则ServerSocketChannel就处于 OP_ACCEPT状态

                } else if (key.isConnectable()) {
                    // a connection was established with a remote server.
                    // 某个SocketChannel完成了和对端的三次握手，则SocketChannel就处于 OP_CONNECT 状态

                } else if (key.isReadable()) {
                    // a channel is ready for reading
                    //SocketChannel通道中数据可读

                } else if (key.isWritable()) {
                    // a channel is ready for writing
                    //SocketChannel可以向通道中写入数据

                }
                // 事件发生后，要么处理，要么取消（cancel），不能什么都不做，否则下次该事件仍会触发，这是因为 nio 底层使用的是水平触发
                // 每次获取 SelectionKey后，都要手动移除，否则 该SelectionKey 会一直存在于 selector.selectedKeys()的结果中
                keyIterator.remove();
            }
        }

    }
}
